package meta.entidad.comun.control.acceso;

import adalid.core.*;
import adalid.core.annotations.*;
import adalid.core.enums.*;
import adalid.core.interfaces.*;
import adalid.core.parameters.*;
import adalid.core.properties.*;
import java.lang.reflect.Field;
import meta.proyecto.base.ProyectoBase;

/**
 * @author Jorge Campins
 */
@EntityClass(independent = Kleenean.TRUE, resourceType = ResourceType.OPERATION, resourceGender = ResourceGender.MASCULINE)
@EntitySelectOperation(enabled = Kleenean.TRUE)
@EntityInsertOperation(enabled = Kleenean.TRUE)
@EntityUpdateOperation(enabled = Kleenean.TRUE)
@EntityDeleteOperation(enabled = Kleenean.TRUE)
@EntityTableView(enabled = Kleenean.TRUE, inserts = Kleenean.TRUE, updates = Kleenean.TRUE)
@EntityDetailView(enabled = Kleenean.TRUE)
@EntityTreeView(enabled = Kleenean.FALSE)
@EntityConsoleView(enabled = Kleenean.TRUE)
@EntityTriggers(afterValue = Kleenean.TRUE)
public class Usuario extends AbstractPersistentEntity {

    // <editor-fold defaultstate="collapsed" desc="class constructors">
    @Deprecated
    private Usuario() {
        this(null, null);
    }

    public Usuario(Artifact declaringArtifact, Field declaringField) {
        super(declaringArtifact, declaringField);
    }
    // </editor-fold>

    @PrimaryKey
    public LongProperty idUsuario;

    @VersionProperty
    public LongProperty versionUsuario;

    @BusinessKey
    @PropertyField(update = Kleenean.FALSE)
    public StringProperty codigoUsuario;

    @NameProperty
    public StringProperty nombreUsuario;

    @PropertyField(auditable = Kleenean.FALSE, password = Kleenean.TRUE, hidden = Kleenean.TRUE, filter = Kleenean.FALSE)
    @StringField(maxLength = 32)
    public StringProperty passwordUsuario;

    @StringField(maxLength = 100)
    @PropertyField(table = Kleenean.TRUE, report = Kleenean.TRUE)
    public StringProperty correoElectronico;

    @ColumnField(nullable = Kleenean.FALSE)
    @PropertyField(create = Kleenean.FALSE, update = Kleenean.FALSE, table = Kleenean.TRUE, report = Kleenean.TRUE)
    public BooleanProperty esSuperUsuario;

    @ColumnField(nullable = Kleenean.FALSE)
    @PropertyField(create = Kleenean.FALSE, update = Kleenean.FALSE, table = Kleenean.TRUE, report = Kleenean.TRUE)
    public BooleanProperty esUsuarioEspecial;

    @InactiveIndicator
    @ColumnField(nullable = Kleenean.FALSE)
    @PropertyField(create = Kleenean.FALSE, update = Kleenean.FALSE, table = Kleenean.TRUE, report = Kleenean.TRUE)
    public BooleanProperty esUsuarioInactivo;

    @ColumnField(nullable = Kleenean.FALSE)
    @PropertyField(create = Kleenean.FALSE, update = Kleenean.FALSE, hidden = Kleenean.TRUE)
    public BooleanProperty esUsuarioModificado;

    @ForeignKey(onDelete = OnDeleteAction.NONE, onUpdate = OnUpdateAction.NONE)
    @ManyToOne(navigability = Navigability.UNIDIRECTIONAL, view = MasterDetailView.NONE)
    @Allocation(maxDepth = 1, maxRound = 0)
    @PropertyField(create = Kleenean.FALSE, update = Kleenean.FALSE, table = Kleenean.TRUE, report = Kleenean.TRUE)
    public Usuario idUsuarioSupervisor;

    public Instance ADMINISTRADOR;

    public Instance AUDITOR;

    public Instance OPERADOR;

    private Segment usuarioActual, demasUsuarios;

    private Segment usuariosEspeciales, usuariosOrdinarios;

    private Segment superUsuarios, usuariosEstandar;

    private Segment usuariosActivos, usuariosInactivos;

    protected State eliminable, modificable, designableComoSuper, superAnulable, desactivable, reactivable;

    protected Transition modificacion, designacion, anulacion, desactivacion, reactivacion;

    protected DesignarSuper designarSuper;

    protected AnularSuper anularSuper;

    protected Desactivar desactivar;

    protected Reactivar reactivar;

    protected Sincronizar sincronizar;

    protected AsignarPassword asignarPassword;

    protected AsignarSupervisor asignarSupervisor;

    protected CambiarPassword cambiarPassword;

    @Override
    protected void settleAttributes() {
        super.settleAttributes();
        setSchema(ProyectoBase.getEsquemaEntidadesComunes());
        setDefaultLabel("usuario");
//      setDefaultShortLabel("usuario");
        setDefaultCollectionLabel("usuarios");
//      setDefaultCollectionShortLabel("usuarios");
    }

    @Override
    protected void settleProperties() {
        super.settleProperties();
        esSuperUsuario.setInitialValue(false);
        esSuperUsuario.setDefaultValue(false);
        esUsuarioEspecial.setInitialValue(false);
        esUsuarioEspecial.setDefaultValue(false);
        esUsuarioInactivo.setInitialValue(false);
        esUsuarioInactivo.setDefaultValue(false);
        esUsuarioModificado.setInitialValue(false);
        esUsuarioModificado.setDefaultValue(false);
        idUsuarioSupervisor.setDefaultLabel("usuario supervisor");
        idUsuarioSupervisor.setDefaultShortLabel("supervisor");
        idUsuarioSupervisor.setDefaultTooltip("código del usuario supervisor");
        idUsuarioSupervisor.setDefaultShortDescription("usuario que supervisa a este usuario");
//
//      ArtifactWrapper.getSomeLabel() obtiene el valor por omisión de las etiquetas de código, nombre, etc.
//
//      idUsuarioSupervisor.codigoUsuario.setDefaultLabel("código supervisor");
//      idUsuarioSupervisor.codigoUsuario.setDefaultShortLabel("código supervisor");
//      idUsuarioSupervisor.nombreUsuario.setDefaultLabel("nombre supervisor");
//      idUsuarioSupervisor.nombreUsuario.setDefaultShortLabel("nombre supervisor");
    }

    @Override
    protected void settleInstances() {
        super.settleInstances();
        ADMINISTRADOR.newInstanceField(idUsuario, 101);
        ADMINISTRADOR.newInstanceField(codigoUsuario, "admin");
        ADMINISTRADOR.newInstanceField(nombreUsuario, "Administrador");
        ADMINISTRADOR.newInstanceField(passwordUsuario, "08b34b490b607342b007843310a284c6"); // sesamo
        ADMINISTRADOR.newInstanceField(esSuperUsuario, true);
        ADMINISTRADOR.newInstanceField(esUsuarioEspecial, true);
        AUDITOR.newInstanceField(idUsuario, 102);
        AUDITOR.newInstanceField(codigoUsuario, "audit");
        AUDITOR.newInstanceField(nombreUsuario, "Auditor");
        AUDITOR.newInstanceField(passwordUsuario, "08b34b490b607342b007843310a284c6"); // sesamo
        AUDITOR.newInstanceField(esSuperUsuario, false);
        AUDITOR.newInstanceField(esUsuarioEspecial, true);
        OPERADOR.newInstanceField(idUsuario, 103);
        OPERADOR.newInstanceField(codigoUsuario, "oper");
        OPERADOR.newInstanceField(nombreUsuario, "Operador");
        OPERADOR.newInstanceField(passwordUsuario, "08b34b490b607342b007843310a284c6"); // sesamo
        OPERADOR.newInstanceField(esSuperUsuario, false);
        OPERADOR.newInstanceField(esUsuarioEspecial, true);
    }

    @Override
    protected void settleExpressions() {
        super.settleExpressions();
        usuarioActual = codigoUsuario.isEqualTo(SpecialCharacterValue.CURRENT_USER_CODE);
        usuarioActual.setDefaultErrorMessage("el usuario no es su propio usuario");
        /**/
        demasUsuarios = codigoUsuario.isNotEqualTo(SpecialCharacterValue.CURRENT_USER_CODE);
        demasUsuarios.setDefaultErrorMessage("el usuario es su propio usuario");
        /**/
        usuariosEspeciales = esUsuarioEspecial.isTrue();
        usuariosEspeciales.setDefaultErrorMessage("el usuario no es un usuario especial");
        /**/
        usuariosOrdinarios = esUsuarioEspecial.isFalse();
        usuariosOrdinarios.setDefaultErrorMessage("el usuario es un usuario especial");
        /**/
        superUsuarios = esSuperUsuario.isTrue();
        superUsuarios.setDefaultErrorMessage("el usuario no es un súper usuario");
        /**/
        usuariosEstandar = esSuperUsuario.isFalse();
        usuariosEstandar.setDefaultErrorMessage("el usuario es un súper usuario");
        /**/
        usuariosActivos = esUsuarioInactivo.isFalse();
        usuariosActivos.setDefaultErrorMessage("el usuario es un usuario inactivo");
        /**/
        usuariosInactivos = esUsuarioInactivo.isTrue();
        usuariosInactivos.setDefaultErrorMessage("el usuario es un usuario activo");
        /**/
        eliminable = usuariosOrdinarios.and(demasUsuarios);
        modificable = eliminable.and(usuariosActivos);
        designableComoSuper = modificable.and(usuariosEstandar);
        superAnulable = modificable.and(superUsuarios);
        desactivable = modificable.isTrue();
        reactivable = eliminable.and(usuariosInactivos);
    }

    @Override
    protected void settleFilters() {
        super.settleFilters();
        setUpdateFilter(modificable);
        setDeleteFilter(eliminable);
    }

    @Override
    protected void settleTransitions() {
        super.settleTransitions();
        designacion.settle(designableComoSuper, superAnulable);
        anulacion.settle(superAnulable, designableComoSuper);
        desactivacion.settle(desactivable, reactivable);
        reactivacion.settle(reactivable, desactivable);
        modificacion.settle(modificable, modificable);
    }

    @Override
    protected void settleOperations() {
        super.settleOperations();
        designarSuper.addTransition(designacion);
        anularSuper.addTransition(anulacion);
        desactivar.addTransition(desactivacion);
        reactivar.addTransition(reactivacion);
        asignarPassword.addTransition(modificacion);
        asignarSupervisor.addTransition(modificacion);
    }

    // <editor-fold defaultstate="collapsed" desc="Operations">
    @OperationClass(access = OperationAccess.PROTECTED)
    public class DesignarSuper extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

        @Override
        protected void settleParameters() {
            super.settleParameters();
            usuario.setSearchQueryFilter(usuario.esUsuarioEspecial.isFalse()
                .and(usuario.esSuperUsuario.isFalse())
                .and(usuario.codigoUsuario.isNotEqualTo(SpecialCharacterValue.CURRENT_USER_CODE)));
            usuario.getSearchQueryFilter().setDefaultErrorMessage(""
                + "el usuario es un usuario especial, es su propio usuario, o ya es un súper-usuario"
                + "");
        }

    }

    @OperationClass(access = OperationAccess.PROTECTED)
    public class AnularSuper extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

        @Override
        protected void settleParameters() {
            super.settleParameters();
            usuario.setSearchQueryFilter(usuario.esUsuarioEspecial.isFalse()
                .and(usuario.esSuperUsuario.isTrue())
                .and(usuario.codigoUsuario.isNotEqualTo(SpecialCharacterValue.CURRENT_USER_CODE)));
            usuario.getSearchQueryFilter().setDefaultErrorMessage(""
                + "el usuario es un usuario especial, es su propio usuario, o no es un súper-usuario"
                + "");
        }

    }

    @OperationClass(access = OperationAccess.PROTECTED)
    public class Desactivar extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

        @Override
        protected void settleParameters() {
            super.settleParameters();
            usuario.setSearchQueryFilter(usuario.esUsuarioEspecial.isFalse()
                .and(usuario.esUsuarioInactivo.isFalse())
                .and(usuario.codigoUsuario.isNotEqualTo(SpecialCharacterValue.CURRENT_USER_CODE)));
            usuario.getSearchQueryFilter().setDefaultErrorMessage(""
                + "el usuario es un usuario especial, es su propio usuario, o ya es un usuario inactivo"
                + "");
        }

    }

    @OperationClass(access = OperationAccess.PROTECTED)
    public class Reactivar extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

        @Override
        protected void settleParameters() {
            super.settleParameters();
            usuario.setSearchQueryFilter(usuario.esUsuarioEspecial.isFalse()
                .and(usuario.esUsuarioInactivo.isTrue())
                .and(usuario.codigoUsuario.isNotEqualTo(SpecialCharacterValue.CURRENT_USER_CODE)));
            usuario.getSearchQueryFilter().setDefaultErrorMessage(""
                + "el usuario es un usuario especial, es su propio usuario, o no es un usuario inactivo"
                + "");
        }

    }

    @OperationClass(access = OperationAccess.PROTECTED)
    public class Sincronizar extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

    }

    @OperationClass(access = OperationAccess.PROTECTED)
    public class AsignarPassword extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

        @ParameterField(auditable = Kleenean.FALSE, password = Kleenean.TRUE, required = Kleenean.TRUE)
        @StringField(maxLength = 32)
        protected StringParameter password;

        @Override
        protected void settleParameters() {
            super.settleParameters();
            usuario.setSearchQueryFilter(usuario.esUsuarioEspecial.isFalse()
                .and(usuario.codigoUsuario.isNotEqualTo(SpecialCharacterValue.CURRENT_USER_CODE)));
            usuario.getSearchQueryFilter().setDefaultErrorMessage(""
                + "el usuario es un usuario especial, o es su propio usuario"
                + "");
        }

    }

    @OperationClass(access = OperationAccess.PROTECTED)
    public class AsignarSupervisor extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

        @ParameterField(required = Kleenean.TRUE)
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario supervisor;

        @Override
        protected void settleParameters() {
            super.settleParameters();
            usuario.setSearchQueryFilter(usuario.esUsuarioEspecial.isFalse()
                .and(usuario.codigoUsuario.isNotEqualTo(SpecialCharacterValue.CURRENT_USER_CODE)));
            usuario.getSearchQueryFilter().setDefaultErrorMessage(""
                + "el usuario es un usuario especial, o es su propio usuario"
                + "");
        }

    }

    @OperationClass(access = OperationAccess.PRIVATE)
    public class CambiarPassword extends ProcessOperation {

        @InstanceReference
        @Allocation(maxDepth = 1, maxRound = 0)
        protected Usuario usuario;

        @ParameterField(auditable = Kleenean.FALSE, password = Kleenean.TRUE, required = Kleenean.TRUE)
        @StringField(maxLength = 32)
        protected StringParameter password;

        @ParameterField(auditable = Kleenean.FALSE, password = Kleenean.TRUE, required = Kleenean.TRUE)
        @StringField(maxLength = 32)
        protected StringParameter nuevoPassword;

        @ParameterField(auditable = Kleenean.FALSE, password = Kleenean.TRUE, required = Kleenean.TRUE)
        @StringField(maxLength = 32)
        protected StringParameter confirmacionPassword;

        @Override
        protected void settleParameters() {
            super.settleParameters();
            password.setDefaultLabel("contraseña");
            password.setDefaultDescription("contraseña actual");
            nuevoPassword.setDefaultLabel("nueva contraseña");
            confirmacionPassword.setDefaultLabel("nueva contraseña");
            confirmacionPassword.setDefaultDescription("confirmación de la nueva contraseña");
        }

    }
    // </editor-fold>

}
